//////////////////////////////////////////////////////////////////////////
//
// This file is a part of XORT project.
//
// PROJECT:         Xort compiler
// FILE:            dasm.h
// AUTHOR:          Vladimir Gumenuk
// DATE:            27-Mar-2008
// MODIFICATIONS:
//
//
//     Copyright(c) 2014, Vladimir Gumenuk
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification, 
//     are permitted provided that the following conditions are met :
//
//     1. Redistributions of source code must retain the above copyright notice, 
//        this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//        the following disclaimer in the documentation and / or other materials provided with the distribution.
//     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse 
//        or promote products derived from this software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
//     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
//     THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
//     OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
//     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "xort.h"

string get_constant( BYTEARRAY buf, dword dwStartFrom, dword dwType, XELEMENT xdata )
{
    string sConst;

    xdata.bType = dwType;
    switch( dwType )
    {
    case t_s1:
        xdata._s1 = buf.getByte( dwStartFrom );
        sConst.Format( "%d", xdata._s1 );
        break;
    case t_u1:
        xdata._u1 = buf.getByte( dwStartFrom );
        sConst.Format( "0x%02X", xdata._u1 );
        break;
    case t_s2:
        xdata._s2 = buf.getShort( dwStartFrom );
        sConst.Format( "%d", xdata._s2 );
        break;
    case t_u2:
        xdata._u2 = buf.getWord( dwStartFrom );
        sConst.Format( "%u", xdata._u2 );
        break;
    case t_s4:
        xdata._s4 = buf.getInt( dwStartFrom );
        sConst.Format( "%d", xdata._s4 );
        break;
    case t_u4:
        xdata._u4 = buf.getDword( dwStartFrom );
        sConst.Format( "%u", xdata._u4 );
        break;
    case t_s8:
        xdata._s8 = buf.getLong( dwStartFrom );
        sConst.Format( "%lld", xdata._s8 );
        break;
    case t_u8:
        xdata._u8 = buf.getQword( dwStartFrom );
        sConst.Format( "%llu", xdata._u8 );
        break;
    case t_r4:
        xdata._r4 = buf.getFloat( dwStartFrom );
        sConst.Format( "%.6f", xdata._r4 );
        break;
    case t_r8:
        xdata._r8 = buf.getDouble( dwStartFrom );
        sConst.Format( "%.12f", xdata._r8 );
        break;
    case t_p:
        xdata._u4 = buf.getDword( dwStartFrom );
        sConst.Format( "0x%08X", xdata._u4 );
        break;
    default:
        sConst.Assign( "INTERNAL ERROR: get_constant() -> unknown type of the constant" );
        break;
    }

    return sConst;
}

string get_constant_text( dword dwType, XELEMENT xdata )
{
    string sConst;

    xdata.bType = dwType;
    switch( dwType )
    {
    case t_s1:
        sConst.Format( "%d", xdata._s1 );
        break;
    case t_u1:
        sConst.Format( "0x%02X", xdata._u1 );
        break;
    case t_s2:
        sConst.Format( "%d", xdata._s2 );
        break;
    case t_u2:
        sConst.Format( "%u", xdata._u2 );
        break;
    case t_s4:
        sConst.Format( "%d", xdata._s4 );
        break;
    case t_u4:
        sConst.Format( "%u", xdata._u4 );
        break;
    case t_s8:
        sConst.Format( "%lld", xdata._s8 );
        break;
    case t_u8:
        sConst.Format( "%llu", xdata._u8 );
        break;
    case t_r4:
        sConst.Format( "%.6f", xdata._r4 );
        break;
    case t_r8:
        sConst.Format( "%.12f", xdata._r8 );
        break;
    case t_p:
        sConst.Format( "0x%08X", xdata._u4 );
        break;
    default:
        sConst.Assign( "INTERNAL ERROR: get_constant() -> unknown type of the constant" );
        break;
    }

    return sConst;
}

string decode_conv( byte bTT )
{
    string strInstr;
    byte bDst = bTT & 0xF0;
    byte bSrc = bTT & 0x0F;
    bSrc <<= 4;

    string csDst = x_type2str( bDst );
    string csSrc = x_type2str( bSrc );
    strInstr.Format( "convert.%s%s", CONST_CHAR_PTR csSrc, CONST_CHAR_PTR csDst );

    return strInstr;
}

string decode_TypeTypeByte( byte bTT )
{
    string strInstr;
    byte bDst = bTT & 0xF0;
    byte bSrc = bTT & 0x0F;
    bSrc <<= 4;

    string csDst = x_type2str( bDst );
    string csSrc = x_type2str( bSrc );

    if( bDst && bSrc ) {
        strInstr.Format( "%s%s", CONST_CHAR_PTR csSrc, CONST_CHAR_PTR csDst );
    } else if( bDst ) {
        return csDst;
    } else if( bSrc ) {
        return csSrc;
    }

    return strInstr;
}

STATIC int get_meta_instr( byte bCode, BYTE_ARRAY PTR buf, dword dwStartFrom, InstructionDataRef decData, int bGetFromDecData )
{
    string strCode = bGetFromDecData ? 
        get_constant_text( t_u2, decData.m_Value ) :
        get_constant( DEREF( buf ), dwStartFrom, t_u2, decData.m_Value );

    switch( bCode )
    {
    case p_label:
        decData.m_strInstr.Format( "__@L%s:", CONST_CHAR_PTR strCode );
        break;

    case p_stkvar:
        decData.m_strInstr.Format( "@stkvar_%s", CONST_CHAR_PTR strCode );
        break;

    case p_endstkvar:
        decData.m_strInstr.Format( "@end_stkvar_%s", CONST_CHAR_PTR strCode );
        break;

    case p_beginarg:
        decData.m_strInstr.Format( "@begin_arg_%s", CONST_CHAR_PTR strCode );
        break;

    case p_endarg:
        decData.m_strInstr.Format( "@end_arg_%s", CONST_CHAR_PTR strCode );
        break;

    case p_begincall:
        decData.m_strInstr.Format( "@begincall_%s", CONST_CHAR_PTR strCode );
        break;

    case p_endcall:
        decData.m_strInstr.Format( "@endcall_%s", CONST_CHAR_PTR strCode );
        break;

    case p_begin_if:
        decData.m_strInstr.Format( "@begin_if_%s", CONST_CHAR_PTR strCode );
        break;

    case p_end_if:
        decData.m_strInstr.Format( "@end_if_%s", CONST_CHAR_PTR strCode );
        break;

    case p_beginret:
        decData.m_strInstr.Format( "@begin_ret_%s", CONST_CHAR_PTR strCode );
        break;

    case p_endret:
        decData.m_strInstr.Format( "@end_ret_%s", CONST_CHAR_PTR strCode );
        break;

    case p_beginasgn:
        decData.m_strInstr.Format( "@begin_asgn_%s", CONST_CHAR_PTR strCode );
        break;

    case p_endasgn:
        decData.m_strInstr.Format( "@end_asgn_%s", CONST_CHAR_PTR strCode );
        break;

    case p_begswitch:
        decData.m_strInstr.Format( "@begin_switch_%s", CONST_CHAR_PTR strCode );
        break;

    case p_endswitch:
        decData.m_strInstr.Format( "@end_switch_%s", CONST_CHAR_PTR strCode );
        break;

    case p_begcase:
        decData.m_strInstr.Format( "@begin_case_%s", CONST_CHAR_PTR strCode );
        break;

    case p_endcase:
        decData.m_strInstr.Format( "@end_case_%s", CONST_CHAR_PTR strCode );
        break;

    default:
        return ERR_UNKNOWN_PRIMCODE;
    }

    decData.m_dwShiftToNext = 3;
    return XORT_OK;
}

int decode_instr( BYTEARRAY buf, dword dwStartFrom, InstructionDataRef decData )
{
    dword i = dwStartFrom;
    byte bCode = buf.get( i ); ++i;
    byte bTypeAddr = buf.get( i ); ++i;
    string strCode;

    decData.m_bInstrCode = bCode;
    decData.m_bTypeAddr  = bTypeAddr;
    decData.m_dwShiftToNext = 0;
    decData.m_strInstr.Empty();
    decData.m_Value.Clear();
    decData.m_Value2.Clear();

    if( bCode == p_convert ) {
        decData.m_dwShiftToNext = 2;
        decData.m_strInstr = decode_conv( bTypeAddr );
        return XORT_OK;
    }

    if( bCode == p_lor || bCode == p_land ) {
        decData.m_dwShiftToNext = 2;
        strCode = decode_TypeTypeByte( bTypeAddr );
        if( bCode == p_lor )
            decData.m_strInstr.Format( "lor.%s", CONST_CHAR_PTR strCode );
        else
            decData.m_strInstr.Format( "land.%s", CONST_CHAR_PTR strCode );
        return XORT_OK;
    }

    if( x_is_metainstruction( bCode ) )
    {
        return get_meta_instr( bCode, ADDROF( buf ), --i, decData, FALSE );
    }

    strCode = xPrimFindAsmString( bCode, bTypeAddr ); // here is the most slow place in the compiler!
    if( strCode.IsEmpty() ) {
        return FALSE;
    }

    decData.m_dwShiftToNext = 2; // size of code byte and address/operand byte

    byte bType = bTypeAddr & 0xF0;
    byte bAddr = bTypeAddr & 0x0F;
    string csConst, csConst2;

    switch( bAddr )
    {
    case a_c:
        csConst = get_constant( buf, i, bType, decData.m_Value );
        if( bCode == p_goto ) {
            decData.m_strInstr.Format( "%s    __@L%s", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        } else {
            decData.m_strInstr.Format( "%s    %s", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        }
        decData.m_dwShiftToNext += x_gettypesize( bType );
        break;
    case a_m:
        csConst = get_constant( buf, i, t_u4, decData.m_Value );
        decData.m_strInstr.Format( "%s    M[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        decData.m_dwShiftToNext += 4;
        break;
    case a_s:
        csConst = get_constant( buf, i, t_s2, decData.m_Value );
        decData.m_strInstr.Format( "%s    S[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        decData.m_dwShiftToNext += 2;
        break;
    case a_indm: // no immediate data
    case a_inds:
        break;
    case a_cs:
        csConst = get_constant( buf, i, t_s2, decData.m_Value ); i += 2;
        csConst2 = get_constant( buf, i, bType, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    %s, S[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += x_gettypesize( bType ) + 2;
        break;
    case a_cm:
        csConst = get_constant( buf, i, t_u4, decData.m_Value ); i += 4;
        csConst2 = get_constant( buf, i, bType, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    %s, M[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += x_gettypesize( bType ) + 4;
        break;
    case a_ms:
        csConst = get_constant( buf, i, t_s2, decData.m_Value ); i += 2;
        csConst2 = get_constant( buf, i, t_u4, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    M[%s], S[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += 6;
        break;
    case a_sm:
        csConst = get_constant( buf, i, t_u4, decData.m_Value ); i += 4;
        csConst2 = get_constant( buf, i, t_s2, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    S[%s], M[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += 6;
        break;
    case a_ss:
        csConst = get_constant( buf, i, t_s2, decData.m_Value ); i += 2;
        csConst2 = get_constant( buf, i, t_s2, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    S[%s], S[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += 4;
        break;
    case a_mm:
        csConst = get_constant( buf, i, t_u4, decData.m_Value ); i += 4;
        csConst2 = get_constant( buf, i, t_u4, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    M[%s], M[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += 8;
        break;
    case a_ma:
        csConst = get_constant( buf, i, t_u4, decData.m_Value ); i += 4;
        csConst2 = get_constant( buf, i, t_s2, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    M[%s], A[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += 6;
        break;
    case a_sa:
        csConst = get_constant( buf, i, t_s2, decData.m_Value ); i += 2;
        csConst2 = get_constant( buf, i, t_s2, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    S[%s], A[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += 4;
        break;
    case a_ta: 
        csConst = get_constant( buf, i, t_u4, decData.m_Value );
        decData.m_strInstr.Format( "%s    %s", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        decData.m_dwShiftToNext += 4;
        break;
    case a_ti:
        csConst = get_constant( buf, i, t_u2, decData.m_Value ); i += 2;
        decData.m_strInstr.Format( "%s    T[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        decData.m_dwShiftToNext += 2;
        break;
    default:
        if( bCode == p_ifz || bCode == p_ifnz || bCode == p_ifeq || bCode == p_ifneq || 
            bCode == p_ifgeq || bCode == p_ifleq || bCode == p_ifl || bCode == p_ifg )
        {
            csConst = get_constant( buf, i, t_s2, decData.m_Value );
            decData.m_dwShiftToNext += 2;
            decData.m_strInstr.Format( "%s    __@L%s", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        }
        else if( bCode == p_geti || bCode == p_puti || bCode == p_invokei )
        {
            csConst = get_constant( buf, i, t_u2, decData.m_Value );
            decData.m_dwShiftToNext += 2;
            decData.m_strInstr.Format( "%s    %s", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        }
        else if( bCode == p_calli )
        {
            csConst = get_constant( buf, i, t_u4, decData.m_Value );
            decData.m_dwShiftToNext += 4;
            decData.m_strInstr.Format( "%s    %s", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        }
        else {
            decData.m_strInstr = strCode;
        }
        break;
    }

    return XORT_OK;
}

// FAST version of decoding functions, for XVM only...
// The main deference between common decoding is that this version doesn't decode opcode to string, so many Format function are avoided

// returns the size of the data type
#ifdef __XVM__
static __inline
#endif
dword get_constant_fast( BYTEARRAY buf, dword dwStartFrom, dword dwType, XELEMENT xdata )
{
    xdata.bType = dwType;
    switch( dwType )
    {
    case t_s1: xdata._s1 = buf.getByte( dwStartFrom );        return 1;
    case t_u1: xdata._u1 = buf.getByte( dwStartFrom );        return 1;
    case t_s2: xdata._s2 = buf.getShort( dwStartFrom );       return 2;
    case t_u2: xdata._u2 = buf.getWord( dwStartFrom );        return 2;
    case t_s4: xdata._s4 = buf.getInt( dwStartFrom );         return 4;
    case t_u4: xdata._u4 = buf.getDword( dwStartFrom );       return 4;
    case t_s8: xdata._s8 = buf.getLong( dwStartFrom );        return 8;
    case t_u8: xdata._u8 = buf.getQword( dwStartFrom );       return 8;
    case t_r4: xdata._r4 = buf.getFloat( dwStartFrom );       return 4;
    case t_r8: xdata._r8 = buf.getDouble( dwStartFrom );      return 8;
    case t_p:  xdata._u4 = buf.getDword( dwStartFrom );       return 4;
    default:
        #ifdef __XVM__
        throw ERR_INVALID_TYPE;
        #endif
        return 0;
    }
    return 0;
}

int decode_instr_fast( BYTEARRAY buf, dword dwStartFrom, InstructionDataRef decData )
{
    dword i = dwStartFrom;
    byte bCode = buf.get(i); ++i;
    byte bTypeAddr = buf.get(i); ++i;
    string strCode;

    decData.m_bInstrCode = bCode;
    decData.m_bTypeAddr = bTypeAddr;
    decData.m_dwShiftToNext = 0;
    decData.m_strInstr.Empty();
    decData.m_Value.Clear();
    decData.m_Value2.Clear();

    if( bCode == p_convert || bCode == p_lor || bCode == p_land ) {
        decData.m_dwShiftToNext = 2;
        return XORT_OK;
    }

    if( x_is_metainstruction( bCode ) ) {
        decData.m_dwShiftToNext = 3; --i;
        get_constant_fast( buf, i, t_u2, decData.m_Value ); 
        return XORT_OK;
    }

    decData.m_dwShiftToNext = 2; // size of code byte and address/operand byte

    byte bType = bTypeAddr & 0xF0;
    byte bAddr = bTypeAddr & 0x0F;

    switch( bAddr )
    {
    case a_c: 
        decData.m_dwShiftToNext += get_constant_fast( buf, i, bType, decData.m_Value ); 
        break;
    case a_m:
        decData.m_dwShiftToNext += get_constant_fast( buf, i, t_u4, decData.m_Value );
        break;
    case a_s:
        decData.m_dwShiftToNext += get_constant_fast( buf, i, t_s2, decData.m_Value );
        break;
    case a_indm: // no immediate data
    case a_inds:
        break;
    case a_cs:
        get_constant_fast( buf, i, t_s2, decData.m_Value ); i += 2;
        decData.m_dwShiftToNext += get_constant_fast( buf, i, bType, decData.m_Value2 ) + 2;
        break;
    case a_cm:
        get_constant_fast( buf, i, t_u4, decData.m_Value ); i += 4;
        decData.m_dwShiftToNext += get_constant_fast( buf, i, bType, decData.m_Value2 ) + 4;
        break;
    case a_ms:
        get_constant_fast( buf, i, t_s2, decData.m_Value ); i += 2;
        get_constant_fast( buf, i, t_u4, decData.m_Value2 );
        decData.m_dwShiftToNext += 6;
        break;
    case a_sm:
        get_constant_fast( buf, i, t_u4, decData.m_Value ); i += 4;
        get_constant_fast( buf, i, t_s2, decData.m_Value2 );
        decData.m_dwShiftToNext += 6;
        break;
    case a_ss:
        get_constant_fast( buf, i, t_s2, decData.m_Value ); i += 2;
        get_constant_fast( buf, i, t_s2, decData.m_Value2 );
        decData.m_dwShiftToNext += 4;
        break;
    case a_mm:
        get_constant_fast( buf, i, t_u4, decData.m_Value ); i += 4;
        get_constant_fast( buf, i, t_u4, decData.m_Value2 );
        decData.m_dwShiftToNext += 8;
        break;
    case a_ma:
        get_constant_fast( buf, i, t_u4, decData.m_Value ); i += 4;
        get_constant_fast( buf, i, t_s2, decData.m_Value2 );
        decData.m_dwShiftToNext += 6;
        break;
    case a_sa:
        get_constant_fast( buf, i, t_s2, decData.m_Value ); i += 2;
        get_constant_fast( buf, i, t_s2, decData.m_Value2 );
        decData.m_dwShiftToNext += 4;
        break;
    case a_ta:
        decData.m_dwShiftToNext += get_constant_fast( buf, i, t_u4, decData.m_Value );
        break;
    case a_ti:
        decData.m_dwShiftToNext += get_constant_fast( buf, i, t_u2, decData.m_Value );
        break;
    default:
        if( bCode == p_ifz   || bCode == p_ifnz  || bCode == p_ifeq || bCode == p_ifneq ||
            bCode == p_ifgeq || bCode == p_ifleq || bCode == p_ifl  || bCode == p_ifg )
        {
            decData.m_dwShiftToNext += get_constant_fast( buf, i, t_s2, decData.m_Value );
        }
        else if( bCode == p_geti || bCode == p_puti || bCode == p_invokei )
        {
            decData.m_dwShiftToNext += get_constant_fast( buf, i, t_u2, decData.m_Value );
        }
        else if ( bCode == p_calli )
        {
            decData.m_dwShiftToNext += get_constant_fast( buf, i, t_u4, decData.m_Value );
        }
        break;
    }

    return XORT_OK;
}

//////////////////////////////////////////////////////////////////////////
// decode_instruction once more - get textual representation of mnemonic
int decode_instr_text( InstructionDataRef decData )
{
    dword i = 0;
    byte bCode = decData.m_bInstrCode; ++i;
    byte bTypeAddr = decData.m_bTypeAddr; ++i;
    string strCode;

    decData.m_dwShiftToNext = 0;
    decData.m_strInstr.Empty();

    if( bCode == p_convert ) {
        decData.m_dwShiftToNext = 2;
        decData.m_strInstr = decode_conv( bTypeAddr );
        return XORT_OK;
    }

    if( bCode == p_lor || bCode == p_land ) {
        decData.m_dwShiftToNext = 2;
        strCode = decode_TypeTypeByte( bTypeAddr );
        if( bCode == p_lor )
            decData.m_strInstr.Format( "lor.%s", CONST_CHAR_PTR strCode );
        else
            decData.m_strInstr.Format( "land.%s", CONST_CHAR_PTR strCode );
        return XORT_OK;
    }

    if( x_is_metainstruction( bCode ) )
    {
        return get_meta_instr( bCode, NULL, 0, decData, TRUE );
    }

    strCode = xPrimFindAsmString( bCode, bTypeAddr ); // here is the most slow place in the compiler!
    if( strCode.IsEmpty() ) {
        return FALSE;
    }

    decData.m_dwShiftToNext = 2; // size of code byte and address/operand byte

    byte bType = bTypeAddr & 0xF0;
    byte bAddr = bTypeAddr & 0x0F;
    string csConst, csConst2;

    switch( bAddr )
    {
    case a_c:
        csConst = get_constant_text( bType, decData.m_Value );
        if( bCode == p_goto ) {
            decData.m_strInstr.Format( "%s    __@L%s", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        } else {
            decData.m_strInstr.Format( "%s    %s", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        }
        decData.m_dwShiftToNext += x_gettypesize( bType );
        break;
    case a_m:
        csConst = get_constant_text( t_u4, decData.m_Value );
        decData.m_strInstr.Format( "%s    M[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        decData.m_dwShiftToNext += 4;
        break;
    case a_s:
        csConst = get_constant_text( t_s2, decData.m_Value );
        decData.m_strInstr.Format( "%s    S[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        decData.m_dwShiftToNext += 2;
        break;
    case a_indm: // no immediate data
    case a_inds:
        break;
    case a_cs:
        csConst = get_constant_text( t_s2, decData.m_Value ); i += 2;
        csConst2 = get_constant_text( bType, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    %s, S[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += x_gettypesize( bType ) + 2;
        break;
    case a_cm:
        csConst = get_constant_text( t_u4, decData.m_Value ); i += 4;
        csConst2 = get_constant_text( bType, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    %s, M[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += x_gettypesize( bType ) + 4;
        break;
    case a_ms:
        csConst = get_constant_text( t_s2, decData.m_Value ); i += 2;
        csConst2 = get_constant_text( t_u4, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    M[%s], S[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += 6;
        break;
    case a_sm:
        csConst = get_constant_text( t_u4, decData.m_Value ); i += 4;
        csConst2 = get_constant_text( t_s2, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    S[%s], M[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += 6;
        break;
    case a_ss:
        csConst = get_constant_text( t_s2, decData.m_Value ); i += 2;
        csConst2 = get_constant_text( t_s2, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    S[%s], S[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += 4;
        break;
    case a_mm:
        csConst = get_constant_text( t_u4, decData.m_Value ); i += 4;
        csConst2 = get_constant_text( t_u4, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    M[%s], M[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += 8;
        break;
    case a_ma:
        csConst = get_constant_text( t_u4, decData.m_Value ); i += 4;
        csConst2 = get_constant_text( t_s2, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    M[%s], A[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += 6;
        break;
    case a_sa:
        csConst = get_constant_text( t_s2, decData.m_Value ); i += 2;
        csConst2 = get_constant_text( t_s2, decData.m_Value2 );
        decData.m_strInstr.Format( "%s    S[%s], A[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst, CONST_CHAR_PTR csConst2 );
        decData.m_dwShiftToNext += 4;
        break;
    case a_ta: 
        csConst = get_constant_text( t_u4, decData.m_Value );
        decData.m_strInstr.Format( "%s    %s", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        decData.m_dwShiftToNext += 4;
        break;
    case a_ti:
        csConst = get_constant_text( t_u2, decData.m_Value ); i += 2;
        decData.m_strInstr.Format( "%s    T[%s]", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        decData.m_dwShiftToNext += 2;
        break;
    default:
        if( bCode == p_ifz || bCode == p_ifnz || bCode == p_ifeq || bCode == p_ifneq || 
            bCode == p_ifgeq || bCode == p_ifleq || bCode == p_ifl || bCode == p_ifg )
        {
            csConst = get_constant_text( t_s2, decData.m_Value );
            decData.m_dwShiftToNext += 2;
            decData.m_strInstr.Format( "%s    __@L%s", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        }
        else if( bCode == p_geti || bCode == p_puti || bCode == p_invokei )
        {
            csConst = get_constant_text( t_u2, decData.m_Value );
            decData.m_dwShiftToNext += 2;
            decData.m_strInstr.Format( "%s    %s", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        }
        else if( bCode == p_calli )
        {
            csConst = get_constant_text( t_u4, decData.m_Value );
            decData.m_dwShiftToNext += 4;
            decData.m_strInstr.Format( "%s    %s", CONST_CHAR_PTR strCode, CONST_CHAR_PTR csConst );
        }
        else {
            decData.m_strInstr = strCode;
        }
        break;
    }

    return XORT_OK;
}

